Subject: Impatience rules
From: [email-masked] (Kevin Bjorke)
To: [email-masked]
Date: Tue, 20 Sep 94 14:40 PDT

Back when Stuart (JG?) posted the first metaforms "link" object, I was
extremely impatient to see it, and 30 miles away from my amiga. So I quickly
whipped-up the program below to use on my IRIS at work (Gee, I actually
remembered the data format by heart!). It displays any LWOB and spins it
around. I tried it with a few models, they all seemed happy. I came across
this hack again this morning and thought someone on the list might have
some use for it someday.

/****************************************************/
/*** gLWOB.c ****************************************/
/*** Very Minimal LWOB display for SGI IRIS GL (tm) */
/*** Kevin Bjorke 11 July 94 ************************/
/****************************************************/
/*** Hit ESC to exit ********************************/
/*** Hit 'P' to toggle points mode ******************/
/*** Hit 'F' to toggle filled poly mode *************/
/*** Arrows and ZERO to turn ************************/
/****************************************************/

#include <stdio.h>
#include <sys/types.h>
#include <malloc.h>
#include <memory.h>
#include <math.h>
#include <gl.h>
#include <device.h>

#define READ_TAG(t)	fread((void *)(&t),sizeof(u_long),1,iff)
#define READ_OFFSET(o)	fread((void *)(&o),sizeof(u_long),1,iff)

typedef float LWval;
typedef struct { LWval x, y, z; } LWpt, *lpp;

FILE *iff;

lpp ptList=0L;
u_long nPts=0;
u_long nPols=0;
u_short *refList=0L;

Boolean shoPoints=FALSE;
Boolean shoPolys=FALSE;
Boolean firstPoint=TRUE;
Boolean knownCtr=FALSE;

LWpt minPt, maxPt, ctrPt;
LWpt range;
Coord wd;

#ifndef MAX
#define MAX(a,b) (((a)<(b))?(b):(a))
#define MIN(a,b) (((a)>(b))?(b):(a))
#endif

/*********************************/
/*********************************/
/*********************************/

static char _junk[8];
char *tag_str(u_long t)
{
    char *cp, *tcp;
    int i;
    tcp = (char *)(&t);
    cp = _junk;
    for (i=0; i<4; ++i) *cp++ = *tcp++;
    _junk[4] = '\0';
    return(_junk);
}

/*********************************/
/*********************************/
/*********************************/

read_pnts(u_long o)
{
    LWpt p;
    u_long i;
    lpp pp;
    nPts = o/sizeof(LWpt);
    printf("%lu Points\n",nPts);
    if (ptList) free((char *)ptList);
    ptList = (lpp)malloc(nPts*sizeof(LWpt));
    if (!ptList) {
	printf("boink\n");
	exit(4);
    }
    for (i=0,pp=ptList; i<nPts; ++i,++pp) {
	fread((void *)(&p),sizeof(LWval),3,iff);
	/* printf("P%4lu: %g %g %g\n",i,p.x,p.y,p.z); */
	pp->x = p.x;
	pp->y = p.y;
	pp->z = p.z;
	if (firstPoint) {
	    firstPoint = FALSE;
	    maxPt.x = minPt.x = p.x;
	    maxPt.y = minPt.y = p.y;
	    maxPt.z = minPt.z = p.z;
	} else {
	    minPt.x = MIN(minPt.x,p.x); maxPt.x = MAX(maxPt.x,p.x);
	    minPt.y = MIN(minPt.y,p.y); maxPt.y = MAX(maxPt.y,p.y);
	    minPt.z = MIN(minPt.z,p.z); maxPt.z = MAX(maxPt.z,p.z);
	}
    }
    return(o);
}

read_pols(u_long o)
{
    int i, j, c;
    nPols = o/(sizeof(u_short));
    printf("%lu polygon refs\n",nPols);
    if (refList) free((char *)refList);
    refList = (u_short *)malloc((size_t)o);
    fread((void *)refList,1,o,iff);
#ifdef YAK
    for (i=0; i<nPols; ) {
	c = refList[i++];
	printf("[%d] ",c);
	for (j=0; j<=c; ++j) {
	    printf("%u ",refList[i++]);
	}
	printf("\n");
    }
    printf("\n");
#endif
    return(o);
}

/*********************************/
/*********************************/
/*********************************/

read_surf(u_long o)
{
    char *a;
    a = malloc((size_t)o);
    if (!a) return(0);
    fread((void *)a,1,o,iff);
    printf("Surf \"%s\"\n",a);
    free(a);
    return(o);
}

/*********************************/
/*********************************/
/*********************************/

read_srfs(u_long o)
{
    char *a;
    a = malloc((size_t)o);
    if (!a) return(0);
    fread((void *)a,1,o,iff);
    printf("Srfs \"%s\"\n",a);
    free(a);
    return(o);
}

/*********************************/
/*********************************/
/*********************************/

#define BS (sizeof(u_long)+sizeof(u_long))
u_long read_chunk(void)
{
    int e;
    u_long tt;
    u_long o;
    if (!(e=READ_TAG(tt)))	return(0);
    if (!(e=READ_OFFSET(o)))	return(0);
    switch (tt) {
    case 'PNTS':	return(BS+read_pnts(o)); break;
    case 'SURF':	return(BS+read_surf(o)); break;
    case 'SRFS':	return(BS+read_srfs(o)); break;
    case 'POLS':	return(BS+read_pols(o)); break;
    default:
	printf("Chunk %s size %lu\n",tag_str(tt),o);
	fseek(iff,(long)o,SEEK_CUR);
	return(BS+o);
    }
}

/*********************************/
/*********************************/
/*********************************/

void lw_vertex(lpp pt)
{
    static float vv[3];
    float d;
    vv[0] = pt->x;
    vv[1] = pt->y;
    vv[2] = pt->z;
    v3f(vv);
}

/*********************************/
/*********************************/
/*********************************/

void calc_window()
{
    if (!knownCtr) {
	ctrPt.x = (minPt.x + maxPt.x)/2.0;
	ctrPt.y = (minPt.y + maxPt.y)/2.0;
	ctrPt.z = (minPt.z + maxPt.z)/2.0;
	fprintf(stderr,"Ctr %g %g %g\n",ctrPt.x,ctrPt.y,ctrPt.z);
	range.x = (maxPt.x - minPt.x);
	range.y = (maxPt.y - minPt.y);
	range.z = (maxPt.z - minPt.z);
	wd = MAX(range.x,range.y);
	wd = MAX(wd,range.z);
	wd *= (1.05/2.);
	knownCtr = TRUE;
    }
    ortho(-wd,wd, -wd,wd, -wd,wd);
}

/*********************************/
/*********************************/
/*********************************/

#define INCR	0x02
#define BASE	0x20
#define LIMT	0xFF

#define RNC	.03

void loopy(void)
{
    u_long i, j, c, f;
    lpp pp;
    u_short *r, n;
    u_long rCtr, gCtr, bCtr, compo;
    long dev;
    short val;
    float rx=(RNC*7.);
    float ry=(RNC*4.);
    float rpx=0.0;
    float rpy=0.0;
    Boolean first=TRUE;
    for(;;) {
	if ((rx!=0.)||(ry!=0.0)||(first)) {
	    first = FALSE;
	    cpack(0L);
	    czclear(0L,getgconfig(GC_ZMAX));
	    calc_window();
	    rot(rpx,'x');
	    rot(rpy,'y');
	    rpx += rx;
	    rpy += ry;
	    translate((Coord)-ctrPt.x,(Coord)-ctrPt.y,(Coord)-ctrPt.z);
	    if (refList && !shoPoints) {
		if (shoPolys) {
		    cpack(0xFFFF0000);
		    rCtr = BASE;
		    gCtr = (BASE<<8);
		    bCtr = (BASE<<16);
		    for (i=0; i<nPols; ) {
			c = refList[i++];
			f = refList[i];
			compo = 0xFF000000 | bCtr | gCtr | rCtr;
			cpack(compo);
			rCtr += INCR;
			if (rCtr > LIMT) {
			    rCtr = BASE;
			    gCtr += (INCR<<8);
			    if (gCtr > (LIMT<<8)) {
				gCtr = (BASE<<8);
				bCtr += (INCR<<16);
				if (bCtr > (LIMT<<16)) {
				    bCtr = (BASE<<16);
				}
			    }
			}
			if (c>1) {
			    bgnpolygon();
				for (j=0; j<c; ++j)
				    lw_vertex(&ptList[refList[i++]]);
			    endpolygon();
			} else {
			    if (c>1) {
				bgnline();
				    for (j=0; j<c; ++j)
					lw_vertex(&ptList[refList[i++]]);
				    lw_vertex(&ptList[f]);
				endline();
			    } else {
				bgnpoint();
				    lw_vertex(&ptList[refList[i++]]);
				endpoint();
			    }
			}
			    ++i;	/* skip surface index */
		    }
		} else {
		    cpack(0xFF0000FF);
		    for (i=0; i<nPols; ) {
			c = refList[i++];
			f = refList[i];
			if (c>1) {
			    bgnline();
				for (j=0; j<c; ++j)
				    lw_vertex(&ptList[refList[i++]]);
				lw_vertex(&ptList[f]);
			    endline();
			} else {
			    bgnpoint();
				lw_vertex(&ptList[refList[i++]]);
			    endpoint();
			}
			    ++i;	/* skip surface index */
		    }
		}
	    } else {
		cpack(0xFFFFFFFF);
		for (i=0,pp=ptList; i<nPts; ++i,++pp) {
		    bgnpoint();
			lw_vertex(pp);
		    endpoint();
		}
	    }
	    swapbuffers();
	    first=FALSE;
	}
	rx = ((rx<(RNC/2.))&&(rx>(-RNC/2.))) ? 0. : rx;
	ry = ((ry<(RNC/2.))&&(ry>(-RNC/2.))) ? 0. : ry;
	if (qtest()||((rx==0.)&&(ry==0.0))) {
	    switch(dev = qread(&val)) {
	    case REDRAW:
		reshapeviewport();
		calc_window();
		first=TRUE;
		break;
	    case FKEY:
		if (val) {
		    shoPolys = !shoPolys;
		    if (shoPolys) shoPoints=FALSE;
		    first=TRUE;
		}
		break;
	    case PKEY:
		if (val) {
		    shoPoints = !shoPoints;
		    if (shoPoints) shoPolys=FALSE;
		    first=TRUE;
		}
		break;
	    case UPARROWKEY:
		if (val) rx += RNC;
		break;
	    case DOWNARROWKEY:
		if (val) rx -= RNC;
		break;
	    case LEFTARROWKEY:
		if (val) ry += RNC;
		break;
	    case RIGHTARROWKEY:
		if (val) ry -= RNC;
		break;
	    case ZEROKEY:
		if (val) {
		    if ((rx==0.)&&(ry==0.)) {
			rpx = rpy = 0.;
			first = TRUE;
		    } else {
			rx = ry = 0.;
		    }
		}
		break;
	    case ESCKEY:
	    case DELKEY:
		exit(0);
		break;
	    }
	}
    }
}

/*********************************/
/*********************************/
/*********************************/

main(int argc,char *argv[])
{
    u_long t, ct;
    u_long o, s, c;
    if (argc<2) {
	fprintf(stderr,"File name, please\n");
	fprintf(stderr,"\t'P' toggles points\n");
	fprintf(stderr,"\t'F' toggles Filled Polys\n");
	fprintf(stderr,"\tArrows and ZERO to turn\n");
	fprintf(stderr,"\tZERO twice to reset\n");
	fprintf(stderr,"\tESC to Quit\n");
	exit(2);
    }
    iff = fopen(argv[1],"r");
    if (!iff) {
	fprintf(stderr,"Bad File Name \"%s\"\n",argv[1]);
	exit(3);
    }
    READ_TAG(t);
    READ_OFFSET(o);
    READ_TAG(ct);
    if (t != 'FORM') {
	fprintf(stderr,"Not a FORM\n");
	fclose(iff);
	exit(3);
    }
    printf("FORM %s size %lu\n",tag_str(ct),o);
    s = 0;
    while (s<o) {
	c = read_chunk();
	if (!c) break;
	s += c;
    }
    fclose(iff);
    if (ptList) {
	foreground();
	keepaspect(1,1);
	winopen("gLWOB");
	calc_window();
	doublebuffer();
	zbuffer(TRUE);
	RGBmode();
	gconfig();
	qdevice(ESCKEY);
	qdevice(PKEY);
	qdevice(FKEY);
	qdevice(UPARROWKEY);
	qdevice(DOWNARROWKEY);
	qdevice(LEFTARROWKEY);
	qdevice(RIGHTARROWKEY);
	qdevice(ZEROKEY);
	loopy();
	free((char *)ptList);
    }
    if (refList) free((char *)refList);
}

/*********************************/
/************************* eof ***/
/*********************************/
-------------------------------------------------------------------------- 
  Kevin Bjorke         |  If you draw a picture, and then draw more and
  Animation Scientist  |  more pictures, and put them on TV, then dino-
  Hi Tech Toons        |  saurs will turn into birds! - Rebecca